from __future__ import with_statement

from crv.model import DBSession, metadata
from crv.model.crvmodel import *
from crv.tools.clustermgr import ClusterMgr
from crv.tools.rolemgr import RoleMgr
from crv.tools.vmmgr import VMMgr
import sys, traceback
import logging
log = logging.getLogger(__name__)

def checkAll2():
    log.debug("checkAll2 Called")
    while True:
        checkAll()


checking=False
previousRunUpdate=-1

def checkAll():
    global checking

    if checking:
        log.info("checkAll checking already, return")
        return

    checking=True

    try:
        doCheckAll()
    except Exception, inst:
        log.error("*** ERRORERROR ***")
        exc_type, exc_value, exc_traceback = sys.exc_info()
        epr=traceback.format_exception(exc_type, exc_value,exc_traceback)
        for i in epr:
            log.error(i)

        checking=False

    finally:
        checking=False
        
def doCheckAll():
    global previousRunUpdate
    
    log.info("#"*256)
    log.info("checkAll Called")
    clMgr=ClusterMgr.getInstance()
    rlMgr=RoleMgr.getInstance()
    vmMgr=VMMgr.getInstance()    

    log.info("Checking VMs")
    vms = DBSession.query(VM).all()
    log.debug("checkAll::vms=%s"%str(vms))

    for ivm in vms:
        log.debug("checking VM:%s"%ivm.getAttr("name"))

        log.debug("getmaker=%s"%str(ivm.rp.getMaker("vm")))

        vmMgr.advanceStates(ivm)
        log.debug("Committing")

                
    log.debug("DIRTY=%s"%str(DBSession.dirty))
    transaction.commit()
    #raw_input("Press key to continue...")


    log.debug("*"*128)
    log.info("Checking Roles")

    roles = DBSession.query(Role).all()
    log.debug("checkAll::roles=%s"%str(roles))
    for irole in roles:
        log.debug("checking Role:%s"%irole.getAttr("name"))
        rlMgr.advanceStates(irole)
        log.debug("Committing")

    log.debug("DIRTY=%s"%str(DBSession.dirty))
    transaction.commit()
    #raw_input("Press key to continue...")

    log.debug("*"*128)

    log.info("Checking Clusters")

    clusters = DBSession.query(Cluster).all()
    log.debug("checkAll::clusters=%s"%str(clusters))
    for icluster in clusters:
        log.debug("checking Cluster:%s"%icluster.getAttr("name"))
        clMgr.advanceStates(icluster)
        log.debug("Committing")

        #Using newRunUpdate and previousRunUpdate to minimize database operations
        #control the interval of profile update
        #If targetSC is not currentSC (meaning it is still in transition) then set a small interval.
        if icluster.targetSC != icluster.currentSC:
            newRunUpdate=30
        else:
            newRunUpdate=60*30

        if newRunUpdate!=previousRunUpdate:
            previousRunUpdate=newRunUpdate
            for irole in icluster.role:
                irole.vm.setAttr("RunUpdate",str(newRunUpdate))
            
    log.debug("DIRTY=%s"%str(DBSession.dirty))
    transaction.commit()
    #raw_input("Press key to continue...")


    #Now for each role that is RUNNING, if CustomRoleAttr is True, will regenerate puppet catalog and reapply them for all its children and its parent role (only If they are already running).

    log.debug("*"*128)
    log.info("CustomRoleAttr Roles")

    roles = DBSession.query(Role).all()
    log.debug("CustomRoleAttr::roles=%s"%str(roles))
    for irole in roles:
        
        if irole.currentSC==irole.SC.SC_RUNNING and irole.targetSC==irole.SC.SC_STARTED and irole.getAttr("CustomAttrChanged")=="True":
            log.debug("CustomAttrChanged for running Role:%s"%irole.getAttr("name"))
            
            irole.setAttr("CustomAttrChanged","False")

            for jrole in (irole.dependBy + irole.dependOn):
                if jrole.currentSC==irole.SC.SC_RUNNING  and irole.targetSC==irole.SC.SC_STARTED:
            
                    #set it to STARTINGVM state, so it will regenerate puppet catalog and reapply it.
                    jrole.setReverseProfileProvided(False)
                    jrole.setReverseProfileApplied(False)
                    jrole.setProfileProvided(False)
                    jrole.setProfileApplied(False)
                    #FIXME: shouldn't change currentSC directly, this is just a hack
                    jrole.currentSC=irole.SC.SC_STARTINGVM
                        
    log.debug("DIRTY=%s"%str(DBSession.dirty))
    transaction.commit()
    #raw_input("Press key to continue...")

    log.debug("*"*128)
    

def buildRoleDep(roles):
    for i in range(len(roles)):
        roles[i].dependOn=[]
#        roles[i].dependOnLocal=[]
        
        for j in range(i):

            if roles[j].roleDef in roles[i].roleDef.dependOn: #i depend on j
                log.debug("buildRoleDep:"+ roles[i].getAttr("name")+ " depends on "+ roles[j].getAttr("name"))
                roles[i].dependOn.append(roles[j])

        for ilc in roles[i].dependOnLocal:
            roles[i].dependOn.append(ilc)
                

